﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace MiniCAP.Core
{
    public class MessagePublisher : IMessagePublisher
    {
        private readonly IMessageStorage _storage;
        private readonly IMessageTransport _transport;
        private IDbTransaction? _currentTransaction;

        public MessagePublisher(IMessageStorage storage, IMessageTransport transport)
        {
            _storage = storage;
            _transport = transport;
        }

        public async Task PublishAsync<T>(string topic, T message, CancellationToken cancellationToken = default)
        {
            await PublishAsync(topic, message, _currentTransaction, cancellationToken);
        }

        public async Task PublishAsync<T>(string topic, T message, IDbTransaction? transaction, CancellationToken cancellationToken = default)
        {
            // 1. 存储消息到数据库  
            var messageId = await _storage.StoreMessageAsync(topic, message, transaction);

            // 2. 如果没有事务，立即发送；否则等待事务提交后发送  
            if (transaction == null)
            {
                await SendMessageAsync(messageId, topic, message);
            }
            else
            {
                // 注册事务提交后的回调  
                RegisterTransactionCallback(transaction, messageId, topic, message);
            }
        }

        private async Task SendMessageAsync<T>(string messageId, string topic, T message)
        {
            try
            {
                var headers = new Dictionary<string, string>
                {
                    ["message-id"] = messageId,
                    ["message-type"] = typeof(T).FullName
                };

                var body = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(message));
                await _transport.SendAsync(topic, body, headers);

                await _storage.UpdateMessageStatusAsync(messageId, MessageStatus.Published);
            }
            catch
            {
                await _storage.UpdateMessageStatusAsync(messageId, MessageStatus.Failed);
                throw;
            }
        }
    }
}
